import time
import json
from django.conf import settings
from asgiref.sync import async_to_sync
from utils.logs import log_running

logger = log_running()


# noinspection PyUnresolvedReferences,PyAttributeOutsideInit
class SendMessageMixin:

    def send_message(self, target_ip, port, msg_id, serializer_class, data):
        serializer = serializer_class(data=data)
        message = {
            'id': msg_id,
            'ip': target_ip,
            'port': port,
            'packet_code': serializer_class.Meta.packet_code,
            'msg': serializer.message.hex(),
            'length': serializer.model.ByteSize()
        }
        async_to_sync(self.layer.send)('bybase', {'type': 'send.message', 'message': message})


# noinspection PyUnresolvedReferences,PyAttributeOutsideInit
class ReceiveMessageMixin:
    def wait_message(self, msg_id, serializer_class, interval, timeout=10):
        """
        等待redis广播的消息，收到消息后进行反序列化
        :param msg_id:
        :param serializer_class:
        :param interval:
        :param timeout:
        :return:
        """
        packet_code = serializer_class.Meta.packet_code
        count_down = timeout * 10
        key = settings.REDIS_BYBASE_PUBLISH_KEY.format(packet_code=packet_code)
        sub = self.redis.pubsub()
        sub.subscribe([key])  # 订阅
        sub.listen()
        item = sub.get_message()
        while not item or item.get('type') != 'message':
            item = sub.get_message()
            time.sleep(interval)
            count_down -= 1
            if count_down <= 0:
                raise Exception('等待超时')
        message = json.loads(item.get('data'))  # redis中存储的是json字符串
        buffer = bytes.fromhex(message.get('content'))  # 将16进制转换成bytes
        serializer = serializer_class(buffer=buffer)  # 进行反序列化
        msg_id_deserialized = serializer.content.get('msg_head').get('trans_id')
        if packet_code == 22:
            # 特殊处理，22的消息包不判断msg_id
            return serializer.content
        if msg_id_deserialized == msg_id:
            return serializer.content
